package com.hangim.pce.common.persistence.dao.impl;

import com.hangim.pce.common.persistence.dao.BaseDao;
import com.hangim.pce.common.persistence.utils.JdbcUtils;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.List;
import java.util.Map;

/**
 * @see BaseDao
 */
public abstract class BaseDaoImpl implements BaseDao {
    /**
     * JdbcTemplate
     */
    protected JdbcTemplate jdbcTemplate;
    /**
     * NamedParameterJdbcTemplate
     */
    protected NamedParameterJdbcTemplate namedParameterJdbcTemplate;
    /**
     * DataSource
     */
    private DataSource dataSource;

    /**
     * 构造函数
     * 使用无参数构造函数时，比如调用init方法执行初始化。
     */
    public BaseDaoImpl() {
    }

    /**
     * 构造函数
     */
    public BaseDaoImpl(DataSource dataSource) {
        init(dataSource);
    }

    /**
     * 初始化
     *
     * @param dataSource DataSource
     */
    protected void init(DataSource dataSource) {
        if (dataSource != null) {
            this.dataSource = dataSource;
            this.jdbcTemplate = new JdbcTemplate(this.dataSource);
            this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(this.dataSource);
        }
    }

    /**
     * @see BaseDao#getDatabaseMetaData()
     */
    @Override
    public DatabaseMetaData getDatabaseMetaData() {
        return this.jdbcTemplate.execute(JdbcUtils::getDatabaseMetaData);
    }

    /**
     * @see BaseDao#getDatabaseType()
     */
    @Override
    public String getDatabaseType() {
        return this.jdbcTemplate.execute((ConnectionCallback<String>) con -> JdbcUtils.getDatabaseType(JdbcUtils.getDatabaseMetaData(con)));
    }

    /**
     * @see BaseDao#createTempTable(List data)
     */
    @Override
    public String createTempTable(List<Long> data) {
        return this.jdbcTemplate.execute((ConnectionCallback<String>) con -> JdbcUtils.createTemporaryTable(con, data));
    }

    /**
     * @see BaseDao#createTempTable(Map nameTypeMap, List data)
     */
    @Override
    public String createTempTable(Map<String, String> nameTypeMap, List<Map<String, Object>> data) {
        return this.jdbcTemplate.execute((ConnectionCallback<String>) con -> JdbcUtils.getDatabaseType(JdbcUtils.getDatabaseMetaData(con)));
    }

    /**
     * @see BaseDao#dropTemporaryTable(String temporaryTableName)
     */
    @Override
    public boolean dropTemporaryTable(String temporaryTableName) {
        return this.jdbcTemplate.execute((ConnectionCallback<Boolean>) con -> {
            JdbcUtils.dropTemporaryTable(con, temporaryTableName);
            return true;
        });
    }

    /**
     * @see BaseDao#getConnection()
     */
    @Override
    public Connection getConnection() throws CannotGetJdbcConnectionException {
        return DataSourceUtils.getConnection(dataSource);
    }

    /**
     * @see BaseDao#releaseConnection(Connection con)
     */
    @Override
    public final void releaseConnection(Connection con) {
        DataSourceUtils.releaseConnection(con, dataSource);
    }

}
